/*
 * Copyright (c) 2008, Yifu Huang
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of SleekIce nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.sleekice.gui;

import com.sleekice.core.Renderable;
import com.sleekice.util.GL;
import com.sleekice.util.List;
import com.sleekice.util.ListNode;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;

public class TextArea implements Renderable, Scrollable, Widget {
    private static final Color DEF_BG_C = GL.bluePowder;
    private static final Color DEF_BORDER_C = Color.black;
    private static final Font DEF_FONT = new Font("Verdana", Font.PLAIN, 12);
    
    /* offsets for the text area from the border */
    private static final int DEF_LEFT_SPC = 10;
    private static final int DEF_RIGHT_SPC = 10;
    private static final int DEF_TOP_SPC = 3;
    private static final int DEF_BOTTOM_SPC = 3;
    private int leftSpc;
    private int rightSpc;
    private int topSpc;
    private int bottomSpc;
    
    /* text vars */
    private Font font;
    private List<TextLine> text;
    private int textWidth;
    
    /* area vars */
    private Color bgC;
    private Color borderC;
    
    private int x;
    private int y;
    private int width;
    private int height;
    
    public TextArea(int x, int y, int width, int height) {
        font = DEF_FONT;
        
        bgC = DEF_BG_C;
        borderC = DEF_BORDER_C;
        
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        
        leftSpc = DEF_LEFT_SPC;
        rightSpc = DEF_RIGHT_SPC;
        topSpc = DEF_TOP_SPC;
        bottomSpc = DEF_BOTTOM_SPC;
        
        textWidth = width-leftSpc-rightSpc;
        
        text = new List<TextLine>();
        
        FontMetrics metrics = GL.g.getFontMetrics(font);
        
        maxLinesInArea = (height-topSpc-bottomSpc)/metrics.getHeight();
    }
    
    public void addText(String str) {
       addText(str, TextLine.DEF_C);
    }
    
    public void addText(String str, Color color) {
       List<String> lines = getStrings(str,font,textWidth);
       ListNode<String> node = lines.getFirst();
       while (node != null) {
           text.add(new TextLine(node.getValue(),color));
           node = node.next();
       }
       if (bar != null) {
           if (text.getTotal() > maxLinesInArea) {
               bar.setMaxValue(text.getTotal()-maxLinesInArea+1);
           }
       }
    }
    
    /**
     * Returns an array of strings with a line break. No word-wrap.
     */
    public static List<String> getStrings(String str, Font font, int lineWidth) {
        FontMetrics metrics = GL.g.getFontMetrics(font);

        List<String> strs = new List<String>();

        int start = 0;
        int end = 0;
        while (end < str.length()) {
            int width = metrics.stringWidth(str.substring(start, end));
            if (width > lineWidth) {
                /**
                 * Find the chopped off word. Starting with the first character
                 * that can fit in this line.
                 */
                int index = end-1;
                while (true) {
                    /* if this whole line doesnt have a space mark, line break */
                    if (index < start) {
                        strs.add(new String(str.substring(start, end)));
                        start = end;
                        break;
                    }
                    /* if there is a space, line break at index */
                    if (str.charAt(index) == ' ') {
                        strs.add(new String(str.substring(start, index)));
                        start = index+1; /* skip the space */
                        end = index+1;
                        break;
                    }
                    index--;
                }
            }
            end++;
        }
        /* add what's left only if its not at the first char */
        if (start != end) {
            strs.add(new String(str.substring(start, end)));
        }

        return strs;
    }

    public void render(Graphics2D g) {
        g.setColor(bgC);
        g.fillRect(x, y, width, height);
        
        g.setFont(font);
        FontMetrics metrics = GL.g.getFontMetrics(font);
        int row = y+metrics.getAscent()+topSpc;
        ListNode<TextLine> node;
        if (bar != null) {
            node = text.getNode(bar.getValue());
        }
        else {
            node = text.getFirst();
        }
        while (node != null) {
            if (row > y+height-bottomSpc) {
                break;
            }
            TextLine temp = node.getValue();
            g.setColor(temp.getColor());
            g.drawString(temp.getText(), x+leftSpc, row);
            row+=metrics.getHeight();
            node = node.next();
        }
        
        g.setColor(borderC);
        g.drawRect(x, y, width, height);
    }
    
    private int maxLinesInArea;
    private ScrollBar bar;
    
    public void initScrollbar(ScrollBar bar) {
        this.bar = bar;
        if (text.getTotal() > maxLinesInArea) {
            bar.setMaxValue(text.getTotal()-maxLinesInArea+1);
        }
        else {
            bar.setMaxValue(0);
        }
    }

    public void scrollDown() {
        bar.increaseValue(1);
    }

    public void scrollUp() {
        bar.increaseValue(-1);
    }

    public boolean isEnabled() {
        return enabled_;
    }

    private boolean visible_ = true;
    public boolean isVisible() {
        return visible_;
    }

    private boolean enabled_ = true;
    public void setEnabled(boolean enabled) {
        enabled_ = true;
    }

    public void setVisible(boolean visible) {
        visible_ = visible;
    }
}
